home *** CD-ROM | disk | FTP | other *** search
- You know my methods. Apply them.
- Sir Arthur Conan Doyle
-
- Using Breakpoints
-
- Introduction
- Types of Breakpoints Supported by SoftICE
- Breakpoint Options
- Execution Breakpoints
- Memory Breakpoints
- Interrupt Breakpoints
- I/O Breakpoints
- Window Message Breakpoints
- Understanding Breakpoint Contexts
- Virtual Breakpoints
- Setting a Breakpoint Action
- Conditional Breakpoints
- Conditional Breakpoint Count Functions
- Using Local Variables in Conditional Expressions
- Referencing the Stack in Conditional Breakpoints
- Performance
- Duplicate Breakpoints
- Elapsed Time
- Breakpoint Statistics
- Referring to Breakpoints in Expressions
- Manipulating Breakpoints
- Using Embedded Breakpoints
-
- Introduction
-
- You can use SoftICE to set breakpoints on program execution, memory
- location reads and writes, interrupts, and reads and writes to I/O
- ports. SoftICE assigns a breakpoint index, from 0 to FF, to each
- breakpoint. You can use this breakpoint index to identify breakpoints
- when you set, delete, disable, enable, or edit them.
-
- All SoftICE breakpoints are sticky, which means that SoftICE tracks
- and maintains a breakpoint until you intentionally clear or disable it
- using the BC or the BD command. After you clear breakpoints, you can
- recall them with the BH command, which displays a breakpoint history.
-
- You can set up to 256 breakpoints at one time in SoftICE. However, the
- number of breakpoints you can set on memory location (BPMs) and I/O
- ports (BPIOs) is a total of four, due to restrictions of the x86
- processors.
-
- Where symbol information is available, you can set breakpoints using
- function names. When in source or mixed mode, you can set
- point-and-shoot style breakpoints on any source code line. A valuable
- feature is that you can set point-and-shoot breakpoints in a module
- before it is even loaded.
-
- Types of Breakpoints Supported by SoftICE
-
- SoftICE provides a powerful array of breakpoint capabilities that take
- full advantage of the x86 architecture, as follows :
-
- * Execution Breakpoints: SoftICE replaces an existing instruction with
- INT 3. You can use the BPX command to set execution breakpoints.
-
- * Memory Breakpoints: SoftICE uses the x86 debug registers to break when
- a certain byte/word/dword of memory is read, written, or executed. You
- can use the BPM command to set memory breakpoints.
-
- * Interrupt Breakpoints: SoftICE intercepts interrupts by modifying the
- IDT (Interrupt Descriptor Table) vectors. You can use the BPINT
- command to set interrupt breakpoints.
-
- * I/O Breakpoints: SoftICE uses a debug register extension available on
- Pentium and Pentium-Pro CPUs to watch for an IN or OUT instruction
- going to a particular port address. You can use the BPIO command to
- set I/O breakpoints.
-
- * Window Message Breakpoints: SoftICE traps when a particular message or
- range of messages arrives at a window. This is not a fundamental
- breakpoint type; it is just a convenient feature built on top of the
- other breakpoint primitives. You can use the BMSG command to set
- window message breakpoints.
-
- Breakpoint Options
-
- You can qualify each type of breakpoint with the following two
- options:
-
- * A conditional expression [IF expression]: The expression must evaluate
- to non-zero (TRUE) for the breakpoint to trigger. Refer to Conditional
- Breakpoints.
-
- * A breakpoint action [DO "command1;command2;"]: A series of SoftICE
- commands can automatically execute when the breakpoint triggers. You
- can use this feature in concert with user-defined macros to automate
- tasks that would otherwise be tedious. Refer to Setting a Breakpoint
- Action on page 114.
-
- Note: For complete information on each breakpoint command, refer to
- the SoftICE Command Reference.
-
- Execution Breakpoints
-
- An execution breakpoint traps executing code such as a function call
- or language statement. This is the most frequently used type of
- breakpoint. By replacing an existing instruction with an INT 3
- instruction, SoftICE takes control when execution reaches the INT 3
- breakpoint.
-
- SoftICE provides two ways for setting execution breakpoints: using a
- mouse and using the BPX command. The following sections describe how
- to use these methods for setting breakpoints.
-
- Using a Mouse to Set Breakpoints
-
- If you are using a Pentium processor and a mouse, you can use the
- mouse to set or clear point-and-shoot (sticky) and one-shot
- breakpoints. To set a sticky breakpoint, double-click the line on
- which you want to set the breakpoint. SoftICE highlights the line to
- indicate that you set a breakpoint. Double-click the line again to
- clear the breakpoint. To set a one-shot breakpoint, click the line on
- which you want to set the breakpoint and use the HERE command (F7) to
- execute to that line.
-
- Using the BPX Command to Set Breakpoints
-
- Use the BPX command with any of the following parameters to set an
- execution breakpoint:
-
- BPX [address] [IF expression] [DO "command1;command2;"]
-
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- Example:
-
- To set a breakpoint on your application's WinMain function, use
- this command:
-
- BPX WinMain
-
- Use the BPX command without specifying any parameter to set a
- point-and-shoot execution breakpoint in the source code. Use Alt-C to
- move the cursor into the Code window. Then use the arrow keys to
- position the cursor on the line on which you want to set the
- breakpoint. Finally, use the BPX command (F9). If you prefer to use
- your mouse to set the breakpoint, click the scroll arrows to scroll
- the Code window, then double-click the line on which you want to set
- the breakpoint.
-
- Memory Breakpoints
-
- A memory breakpoint uses the debug registers found on the 386 CPUs and
- later models to monitor access to a certain memory location. This type
- of breakpoint is extremely useful for finding out when and where a
- program variable is modified, and for setting an execution breakpoint
- in read-only memory. You can only set four memory breakpoints at one
- time, because the CPU contains only four debug registers.
-
- Use the BPM command to set memory breakpoints:
-
- BPM[B|W|D] address [R|W|RW|X] [ debug register] [IF expression]
- [DO "command1;command2;"]
-
- BPM and BPMB:
- Set a byte-size breakpoint.
- BPMW:
- Sets a word (2-byte) size breakpoint.
- BPMD:
- Sets a dword (4-byte) size breakpoint.
- R, W, and RW:
- Break on reads, writes, or both.
- X:
- Breaks on execution; this is more powerful than a BPX-style
- breakpoint because memory does not need to be modified, enabling
- such options as setting breakpoints in ROM or setting breakpoints
- on addresses that are not present.
- debug register:
- Specifies which debug register to use. SoftICE normally manages
- the debug register for you, unless you need to specify it in an
- unusual situation.
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- Example:
-
- The following example sets a memory breakpoint to trigger when a
- value of 5 is written to the Dword (4-byte) variable
- MyGlobalVariable.
-
- BPMD MyGlobalVariable W IF MyGlobalVariable==5
-
- If the target location of a BPM breakpoint is frequently accessed,
- performance can be degraded regardless of whether the conditional
- expression evaluates to FALSE.
-
- Interrupt Breakpoints
-
- Use an interrupt breakpoint to trap an interrupt through the IDT. The
- breakpoint only triggers when a specified interrupt is dispatched
- through the IDT.
-
- Use the BPINT command to set interrupt breakpoints:
-
- BPINT interrupt-number [IF expression] [DO "command1;command2;"]
-
- interrupt-number:
- Number ranging from 0 to 255 (0 to FF hex).
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- If an interrupt is caused by a software INT instruction, the
- instruction displayed will be the INT instruction. (SoftICE pops up
- when execution reaches the INT instruction responsible for the
- breakpoint, but before the instruction actually executes.) Otherwise,
- the current instruction will be the first instruction of an interrupt
- handler. You can list all interrupts and their handlers by using the
- IDT command.
-
- Example:
-
- Use the following command to set a breakpoint to trigger when a
- call to the kernel-mode routine NtCreateProcess is made from user
- mode:
-
- BPINT 2E IF EAX==1E
-
- Note: The NtCreateProcess is normally called from ZwCreateProcess
- in the NTDLL.DLL, which is in turn called from CreateProcessW in
- the KERNEL32.DLL. In the conditional expression, 1E is the
- service number for NtCreateProcess. Use the NTCALL command to
- find this value.
-
- You can use the BPINT command to trap software interrupts, for
- example, INT 21 made by 16-bit Windows programs. Note that software
- interrupts issued from V86 mode do not pass through the IDT vector
- that they specify. INT instructions executed in V86 generate processor
- general protection faults (GPF), which are handled by vector 0xD in
- the IDT. The Windows GPF handler realizes the cause of the fault and
- passes control to a handler dedicated to specific V86 interrupt types.
- The types may end up reflecting the interrupt down to V86 mode by
- calling the interrupt handler entered in the V86 mode Interrupt Vector
- Table (IVT). In some cases, a real-mode interrupt is reflected
- (simulated) by calling the real-mode interrupt vector.
-
- In the case where the interrupt is reflected, you can trap it by
- placing a BPX breakpoint at the beginning of the real-mode interrupt
- handler.
-
- Example:
-
- To set a breakpoint on the real-mode INT 21 handler, use the
- following command:
-
- BPX *($0:(21*4))
-
- I/O Breakpoints
-
- An I/O breakpoint monitors reads and writes to a port address. The
- breakpoint traps when an IN or OUT instruction accesses the port.
- SoftICE implements I/O breakpoints by using the debug register
- extensions introduced with the Pentium. As a result, I/O breakpoints
- require a Pentium or Pentium-Pro CPU. A maximum of four I/O
- breakpoints can be set at one time. The I/O breakpoint is effective in
- kernel-level (ring 0) code as well as user (ring 3) code.
-
- Notes: Under Windows 95, SoftICE relies on the I/O permission bitmap,
- which restricts I/O trapping to ring 3 code.
-
- Notes: You cannot use I/O breakpoints to trap IN/OUT instructions
- executed by MS-DOS programs. The IN/OUT instructions are trapped and
- emulated by the operating system, and therefore do not generate real
- port I/O, at least not in a 1:1 mapping.
-
- Use the BPIO command to set I/O breakpoints:
-
- BPIO port-number [R|W|RW] [IF expression]
- [DO "command1;command2;"]
-
- R, W, and RW :
- Break on reads (IN instructions), writes (OUT instructions), or
- both, respectively.
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- When an I/O breakpoint triggers and SoftICE pops up, the current
- instruction is the instruction following the IN or OUT that caused the
- breakpoint to trigger. Unlike BPM breakpoints, there is no size
- specification; any access to the port-number, whether byte, word, or
- dword, triggers the breakpoint. Any I/O that spans the I/O breakpoint
- will also trigger the breakpoint. For example, if you set an I/O
- breakpoint on port 2FF, a word I/O to port 2FE would trigger the
- breakpoint.
-
- Example:
-
- Use the following command to set a breakpoint to trigger when a
- value is read from port 3FEH with the upper 2 bits set:
-
- BPIO 3FE R IF (AL & C0)==C0
-
- The condition is evaluated after the instruction completes. The
- value will be in AL, AX, or EAX because all port I/O, except for
- the string I/O instructions (which are rarely used), use the EAX
- register.
-
- Window Message Breakpoints
-
- Use a window message breakpoint to trap a certain message or range of
- messages delivered to a window procedure. Although you could implement
- an equivalent breakpoint yourself using BPX with a conditional
- expression, the following BMSG command is easier to use:
-
- BMSG window-handle [L] [ begin-message [ end-message]]
- [IF expression] [DO "command1;command2;"]
-
- window-handle:
- Value returned when the window was created; you can use the HWND
- command to get a list of windows with their handles.
- L:
- Signifies that the window message should be printed to the
- Command window without popping into SoftICE.
- begin-message:
- Single Windows message or the lower message number in a range of
- Windows messages. If you do not specify a range with an
- end-message, then only the begin-message will cause a break. For
- both begin-message and end-message, the message numbers can be
- specified either in hexadecimal or by using the actual ASCII
- names of the messages, for example, WM_QUIT.
- end-message:
- Higher message number in a range of Windows messages.
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- When specifying a message or a message range, you can use the symbolic
- name, for example, WM_NCPAINT. Use the WMSG command to get a list of
- the window messages that SoftICE understands. If no message or message
- range is specified, any message will trigger the breakpoint.
-
- Example:
-
- To set a window message breakpoint for the window handle 1001E,
- use the following command:
-
- BMSG 1001E WM_NCPAINT
-
- SoftICE is smart enough to take into account the address context
- of the process that owns the window, so it does not matter what
- address context you are in when you use BMSG.
-
- You can construct an equivalent BPX-style breakpoint using a
- conditional expression. Use the HWND command to get the address
- of the window procedure, then use the following BPX command
- (Win32 only):
-
- BPX 5FEBDD12 IF (esp->8)==WM_NCPAINT
-
- Warning: When setting a breakpoint using a raw address (not a symbol),
- it is vital to be in the correct address context.
-
- Understanding Breakpoint Contexts
-
- A breakpoint context consists of the address context in which the
- breakpoint was set and in what code module the breakpoint is in, if
- any. Breakpoint contexts apply to the BPX and BPM commands, and
- breakpoint types based on those commands such as BMSG.
-
- For Win32 applications, breakpoints set in the upper 2GB of address
- space are global; they break in any context. Breakpoints set in the
- lower 2GB are context-sensitive; they trigger according to the
- following criteria and SoftICE pops up:
-
- * SoftICE only pops up if the address context matches the context
- in which the breakpoint was set.
-
- * If the breakpoint triggers in the same code module in which the
- breakpoint was set, then SoftICE disregards the address context
- and pops up. This means that a breakpoint set in a shared module
- like KERNEL32.DLL breaks in every address context that has the
- module loaded, regardless of what address context was selected
- when the breakpoint was set.
-
- The exception is if another process mapped the module at a
- different base address than the one in which the breakpoint is
- set. In this case, the breakpoint does not trigger. Avoid this
- situation by basing your DLLs at non-conflicting addresses.
-
- Breakpoints set on MS-DOS and 16-bit Windows programs are
- context-sensitive too in the sense that the breakpoint only affects
- the NTVDM process in which the breakpoint was set. The breakpoint
- never crosses NTVDMs, even if the same program is run multiple times.
-
- Breakpoint contexts are more important for BPM-type breakpoints than
- for BPX. BPM sets an x86 hardware breakpoint that triggers on a
- certain virtual address. Because the CPU's breakpoint hardware knows
- nothing of address spaces, it could potentially trigger on an
- unrelated piece of code or data. Breakpoint contexts give SoftICE the
- ability to discriminate between false traps and real ones.
-
- Virtual Breakpoints
-
- In SoftICE, you can set breakpoints in Windows modules before they
- load, and it is not necessary for a page to be present in physical
- memory for a BPX (INT 3) breakpoint to be set. In such cases, the
- breakpoint is virtual; it will be automatically armed when the module
- loads or the page becomes present. Virtual breakpoints can only be set
- on either symbols or source lines.
-
- Setting a Breakpoint Action
-
- You can set a breakpoint to execute a series of SoftICE commands,
- including user-defined macros, after the breakpoint is triggered. You
- define these breakpoint actions with the DO option, which is available
- with every breakpoint type:
-
- DO "command1;command2;"
-
- The body of a breakpoint action definition is a sequence of SoftICE
- commands or other macros, separated by semicolons. You need not
- terminate the final command with a semicolon.
-
- Breakpoint actions are closely related to macros. Refer to Working
- with Persistent Macros on page 162 for more information about macros.
- Breakpoint actions are essentially unnamed macros that do not accept
- command-line arguments. Breakpoint actions, like macros, can call upon
- macros. In fact a prime use of macros is to simplify the creation of
- complex breakpoint actions.
-
- If you need to embed a literal quote character (") or a percent sign
- (%) within the macro (breakpoint) body, precede the character with a
- backslash character (\). To specify a literal backslash character, use
- two consecutive backslashes (\\).
-
- If a breakpoint is being logged (refer to the built-in function
- BPLOG), the action will not be executed.
-
- The following examples illustrate the basic use of breakpoint actions:
-
- BPX EIP DO "dd eax"
- BPX EIP DO "data 1;dd eax"
- BPMB dataaddr if (byte(*dataaddr)==1) do "? IRQL"
-
- Conditional Breakpoints
-
- Conditional breakpoints provide a fast and easy way to isolate a
- specific condition or state within the system or application you are
- debugging. By setting a breakpoint on an instruction or memory address
- and supplying a conditional expression, SoftICE will only trigger if
- the breakpoint evaluates to non-zero (TRUE). Because the SoftICE
- expression evaluator handles complex expressions easily, conditional
- expressions take you right to the problem or situation you want to
- debug with ease.
-
- All SoftICE breakpoint commands (BPX, BPM, BPIO, BMSG, and BPINT)
- accept conditional expressions using the following syntax:
-
- breakpoint-command [ breakpoint options] [IF conditional expression]
- [DO "commands"]
-
- The IF keyword, when present, is followed by any expression that you
- want to be evaluated when the breakpoint is triggered. The breakpoint
- will be ignored if the conditional expression is FALSE (zero). When
- the conditional expression is TRUE (non-zero), SoftICE pop ups and
- displays the reason for the break, which includes the conditional
- expression.
-
- The following examples show conditional expressions used during the
- development of SoftICE.
-
- Note: Most of these examples contain system-specific values that vary
- depending on the exact version of Windows NT you are running.
-
- * Watch a thread being activated:
-
- bpx ntoskrnl!SwapContext IF (edi==0xFF8B4020)
-
- * Watch a thread being deactivated:
-
- bpx ntoskrnl!SwapContext IF (esi==0xFF8B4020)
-
- * Watch CSRSS HWND objects (type 1) being created:
-
- bpx winsrv!HMAllocObject IF (esp->c == 1)
-
- * Watch CSRSS thread info objects (type 6) being destroyed:
-
- bpx winsrv!HMFreeObject+0x25 IF (byte(esi->8) == 6)
-
- * Watch process object-handle-tables being created:
-
- bpx ntoskrnl!ExAllocatePoolWithTag IF (esp->c == æObtb')
-
- * Watch a thread state become terminated (enum == 4):
-
- bpmb _thread->29 IF byte(_thread->29) == 4)
-
- * Watch a heap block (230CD8) get freed:
-
- bpx ntddl!RtlFreeHeap IF (esp->c == 230CD8)
-
- * Watch a specific process make a system call:
-
- bpint 2E if (process == _process)
-
- Many of the previous examples use the thread and process intrinsic
- functions provided by SoftICE. These functions refer to the active
- thread or process in the operating system. In some cases, the examples
- precede the function name with an underscore "_". This is a special
- feature that makes it easier to refer to a dynamic value such as a
- register's contents or the currently running thread or process as a
- constant. The following examples should help to clarify this concept:
-
- * This example sets a conditional breakpoint that will be triggered if
- the dynamic (run-time) value of the EAX register equals its current
- value.
-
- bpx eip IF (eax == _eax)
-
- This is equivalent to:
-
- ? EAX
- 00010022
- bpx eip IF (eax == 10022)
-
- * This example sets a conditional breakpoint that will be triggered if
- the value of an executing thread's thread-id matches the thread-id of
- the currently executing thread.
-
- bpx eip IF (tid == _tid)
-
- This is equivalent to:
-
- ? tid
- 8
- bpx eip IF (tid == 8)
-
- When you precede a function name or register with an underscore in an
- expression, the function is evaluated immediately and remains constant
- throughout the use of that expression.
-
- Conditional Breakpoint Count Functions
-
- SoftICE supports the ability to monitor and control breakpoints based
- on the number of times a particular breakpoint has or has not been
- triggered. You can use the following count functions in conditional
- expressions:
-
- * BPCOUNT
-
- * BPMISS
-
- * BPTOTAL
-
- * BPLOG
-
- * BPINDEX
-
- BPCOUNT
-
- The value for the BPCOUNT function is the current number of times that
- the breakpoint has been evaluated as TRUE.
-
- Use this function to control the point at which a triggered breakpoint
- causes a popup to occur. Each time the breakpoint is triggered, the
- conditional expression associated with the breakpoint is evaluated. If
- the condition evaluates to TRUE, the breakpoint instance count
- (BPCOUNT) increments by one. If the conditional evaluates to FALSE,
- the breakpoint miss instance count (BPMISS) increments by one.
-
- Example:
-
- The fifth time the breakpoint triggers, the BPCOUNT equals 5, so
- the conditional expression evaluates to TRUE and SoftICE pops up.
-
- bpx myaddr IF (bpcount==5)
-
- Use BPCOUNT only on the righthand side of compound conditional
- expressions for BPCOUNT to increment correctly:
-
- bpx myaddr if (eax==1) && (bpcount==5)
-
- Due to the early-out algorithm employed by the expression evaluator,
- the BPCOUNT==5 expression will not be evaluated unless EAX==1. (The C
- language works the same way.) Therefore, by the time BPCOUNT==5 gets
- evaluated, the expression is TRUE. BPCOUNT will be incremented and if
- it equals 5, the full expression evaluates to TRUE and SoftICE pops
- up. If BPCOUNT != 5, the expression fails, BPMISS is incremented and
- SoftICE will not pop up (although BPCOUNT is now 1 greater).
-
- Once the full expression returns TRUE, SoftICE pops up, and all
- instance counts (BPCOUNT and BPMISS) are reset to 0.
-
- Note: Do not use BPCOUNT before the conditional expression, otherwise
- BPCOUNT will not increment correctly:
-
- bpx myaddr if (bpcount==5) && (eax==1)
-
- BPMISS
-
- The value for the BPMISS expression function is the current number of
- times that the breakpoint was evaluated as FALSE.
-
- The expression function is similar to the BPCOUNT function. Use it to
- specify that SoftICE pop up in situations where the breakpoint is
- continually evaluating to FALSE. The value of BPMISS will always be
- one less than you expect, because it is not updated until the
- conditional expression is evaluated. You can use the (>=) operator to
- correct this delayed update condition.
-
- Example:
-
- bpx myaddr if (eax==43) || (bpmiss>=5)
-
- Due to the early-out algorithm employed by the expression evaluator,
- if the expression eax==43 is ever TRUE, the conditional evaluates to
- TRUE and SoftICE pops up. Otherwise, BPMISS is updated each time the
- conditional evaluates to FALSE. After 5 consecutive failures, the
- expression evaluates to TRUE and SoftICE pops up.
-
- BPTOTAL
-
- The value for the BPTOTAL expression function is the total number of
- times that the breakpoint was triggered.
-
- Use this expression function to control the point at which a triggered
- breakpoint causes a popup to occur. The value of this expression is
- the total number of times the breakpoint was triggered (refer to the
- Hits field in the output of the BSTAT command) over its lifetime. This
- value is never cleared.
-
- Example:
-
- The first 50 times this breakpoint is triggered, the condition
- evaluates to FALSE and SoftICE will not pop up. Every time after
- 50, the condition evaluates to TRUE, and SoftICE pops up on this
- and every subsequent trap.
-
- bpx myaddr if (bptotal > 50)
-
- You can use BPTOTAL to implement functionality identical to that of
- BPCOUNT. Use the modulo "%" operator as follows:
-
- if (!(bptotal%COUNT))
-
- The COUNT is the frequency with which you want the breakpoint to
- trigger. If COUNT is 4, SoftICE pops up every fourth time the
- breakpoint triggers.
-
- BPLOG
-
- Use the BPLOG expression function to log the breakpoint to the history
- buffer. SoftICE does not pop up when logged breakpoints trigger.
-
- Note: Actions only execute when SoftICE pops up, so using actions with
- the BPLOG function is pointless.
-
- The BPLOG expression function always returns TRUE. It causes SoftICE
- to log the breakpoint and relevant information about the breakpoint to
- the SoftICE history buffer.
-
- Example:
-
- Any time the breakpoint triggers and the value of EAX equals 1,
- SoftICE logs the breakpoint in the history buffer. SoftICE will
- not popup.
-
- bpx myaddr if ((eax==1) && bplog)
-
- BPINDEX
-
- Use the BPINDEX expression function to obtain the breakpoint index to
- use with breakpoint actions.
-
- This expression function returns the index of the breakpoint that
- caused SoftICE to pop up. This index is the same index used by the BL,
- BC, BD, BE, BPE, BPT, and BSTAT commands. You can use this value as a
- parameter to any command that is being executed as an action.
-
- Example:
-
- This example of a breakpoint action causes the BSTAT command to
- be executed with the breakpoint that caused the action to be
- executed as its parameter:
-
- bpx myaddr do "bstat bpindex"
-
- This example shows a breakpoint that uses an action to create
- another breakpoint:
-
- bpx myaddr do "t;bpx @esp if(tid==_tid) do \"bc bpindex\";g"
-
- Note: BPINDEX is intended to be used with breakpoint actions, and
- causes an error if it is used within a conditional expression. Its use
- outside of actions is allowed, but the result is unspecified and you
- should not rely on it.
-
- Using Local Variables in Conditional Expressions
-
- SoftICE lets you use local variable names in conditional expressions
- as long as the type ofbreakpoint is an execution breakpoint (BPX or
- BPM X). SoftICE does not recognize local symbols in conditional
- expressions for other breakpoint types, such as BPIO or BPMD RW,
- because they require an execution scope. This type of breakpoint is
- not tied to a specific section of executing code, so local variables
- have no meaning.
-
- When using local variables in conditional expressions, functions
- typically have a prologue where local variables are created and an
- epilogue where they are destroyed. You can access local variables
- after the prologue code completes execution and before the epilogue
- code begins execution. Function parameters are also temporarily
- inaccessible using symbol names during prologue and epilogue
- execution, because of adjustments to the stack frame.
-
- To avoid these restrictions, set a breakpoint on either the first or
- last source code line within the function body. The following concepts
- use the foobar function to explain this concept.
-
- Foobar Function
-
- 1:DWORD foobar ( DWORD foo )
- 2:{
- 3: DWORD fooTmp=0;
- 4:
- 5: if(foo)
- 6: {
- 7: fooTmp=foo*2;
- 8: }else{
- 9: fooTmp=1;
- 10: }
- 11:
- 12: return fooTmp;
- 13:}
-
- Source code lines 1 and 2 are outside the function body. These lines
- execute the prologue code. If you use a local variable at this point,
- you receive the following symbol error:
-
- :BPX foobar if(foo==1)
- error: Undefined Symbol (foo)
-
- Set the conditional on the source code line 3 where the local variable
- fooTmp is declared and initialized, as follows:
-
- :BPX .3 if(foo==0)
-
- Source code line 13 marks the end of the function body. It also begins
- epilogue code execution; thus, local variables and parameters are out
- of scope. To set a conditional at the end of the foobar function, use
- source line 12, as follows:
-
- :BPX.12 if(fooTmp==1)
-
- Note: Although it is possible to use local variables as the input to a
- breakpoint command, such as BPMD RW, you should avoid doing this.
- Local variables are relative to the stack, so their absolute address
- changes each time the function scope where the variable is declared
- executes. When the original function scope exits, the address tied to
- the breakpoint no longer refers to the value of the local variable.
-
- Referencing the Stack in Conditional Breakpoints
-
- If you create your symbol file with full symbol information, you can
- access function parameters and local variables through their symbolic
- names, as described in Using Local Variables in Conditional
- Expressions. If, however, you are debugging without full symbol
- information, you need to reference function parameters and local
- variables on the stack. For example, if you translated a module with
- publics only or you want to debug a function for an operating system,
- reference function parameters and local variables on the stack.
-
- This section is specific to 32-bit flat application or system code.
-
- Function parameters are passed on the stack, so you need to
- de-reference these parameters through the ESP or EBP registers. Which
- one you use depends on the function's prologue and where you set the
- actual breakpoint in relation to that prologue.
-
- Most 32-bit functions have a prologue of the following form:
-
- PUSH EBP
- MOV EBP,ESP
- SUB ESP,size (locals)
-
- Which sets up a stack frame as follows:
-
- Stack Top PARAM n ESP+(n*4), or
- EBP+(n*4)+4 Pushed by
- PARAM #2 ESP+8, or EBP+C Caller
-
- PARAM #1 ESP+4, or EBP+8
-
- RET EIP Stack pointer on
- Entry
- Current Base Pointer (PUSH
- EBP SAVE EBP EBP, MOV EBP,ESP)
- LOCALS+SIZE-1 Call prologue
-
- Stack Pointer after
- LOCALS+0 prologue (SUB ESP,
- size(locals)
-
- SAVE EBX Optional save of "C"
- registers Register
- SAVE ESI saved by
- Stack Current Stack pointer after compiler
- Bottom ESP SAVE EDI registers are saved
-
- Use either the ESP or EBP register to address parameters. Using the
- EBP register is not valid until the PUSH EBP and MOV EBP, ESP
- instructions are executed. Also note that once space for local
- variables is created (SUB ESP,size) the position of the parameters
- relative to ESP needs to be adjusted by the size of the local
- variables and any saved registers.
-
- Typically you set a breakpoint on the function address, for example:
-
- BPX IsWindow
-
- When this breakpoint is triggered, the prologue has not been executed,
- and parameters can easily be accessed through the ESP register. At
- this point, use of EBP is not valid.
-
- To be sure that de-referencing the stack in a conditional expression
- operates as you would expect, use the following guidelines.
-
- Note: This assumes a stack-based calling convention with arguments
- pushed right-to-left.
-
- * If you set a breakpoint at the exact function address, for example,
- BPX IsWindow, use ESP+(param# * 4) to address parameters, where param#
- is 1...n.
-
- * If you set a breakpoint inside a function body (after the full
- prologue has been executed), use EBP+(param# * 4)+4 to address
- parameters, where param# is 1...n. Be sure that the routine does not
- use the EBP register for a purpose other than a stack-frame.
-
- * Functions that are assembly-language based or are optimized for
- frame-pointer omission may require that you use the ESP register,
- because EBP may not be set up correctly.
-
- Note: Once the space for local variables is allocated on the stack,
- the local variables can be addressed using a negative offset from EBP.
- The first local variable is at EBP-4. Simple data types are typically
- Dword sized, so their offset can be calculated in a manner similar to
- function parameters. For example, with two pointer local variables,
- one will be at EBP-4 and the other will be at EBP-8.
-
- Performance
-
- Conditional breakpoints have some overhead associated with run-time
- evaluation. Under most circumstances you see little or no effect on
- performance when using conditional expressions. In situations where
- you set a conditional breakpoint on a highly accessed data variable or
- code sequence, you may notice slower system performance. This is due
- to the fact that every time the breakpoint is triggered, the
- conditional expression is evaluated. If a routine is executed hundreds
- of times per second (such as ExAllocatePool or SwapContext), the fact
- that any type of breakpoint with or without a conditional is trapped
- and evaluated with this frequency results in some performance
- degradation.
-
- Duplicate Breakpoints
-
- Once a breakpoint is set on an address, you cannot set another
- breakpoint on the same address. With conditional expressions, however,
- you can create a compound expression using the logical operators (&&)
- or (||) to test more than one condition at the same address.
-
- Elapsed Time
-
- SoftICE supports using the time stamp counter (RDTSC instruction) on
- all Pentium and Pentium-Pro machines. When SoftICE first starts, it
- displays the clock speed of the machine on which it is running. Every
- time SoftICE pops up due to a breakpoint, the elapsed time displays
- since the last time SoftICE popped up. The time displays after the
- break reason in seconds, milliseconds, or microseconds:
-
- Break due to G (ET=23.99 microseconds)
-
- The Pentium cycle counter is highly accurate, but you must keep the
- following two issues in mind:
-
- 1- There is overhead involved in popping SoftICE up and down. On a
- 100MHz machine, this takes approximately 5 microseconds. This number
- is slightly variable due to caching and privilege level changes.
-
- 2- If a hardware interrupt occurs before the breakpoint goes off, all
- the interrupt processing time is included. Interrupts are off when
- SoftICE pops up, so a hardware interrupt almost always goes off as
- soon as Windows NT resumes.
-
- Breakpoint Statistics
-
- SoftICE collects statistical information about each breakpoint,
- including the following:
-
- * Total number of hits, breaks, misses, and errors
-
- * Current hits and misses
-
- Use the BSTAT command to display this information. Refer to the
- SoftICE Command Reference for more information on the BSTAT command.
-
- Referring to Breakpoints in Expressions
-
- You can combine the prefix "BP" with the breakpoint index to use as a
- symbol in an expression. This works for all BPX and BPM breakpoints.
- SoftICE uses the actual address of the breakpoint.
-
- Example:
-
- To disassemble code at the address of the breakpoint with index
- 0, use the command:
-
- U BP0
-
- Manipulating Breakpoints
-
- SoftICE provides a variety of commands for manipulating breakpoints
- such as listing, modifying, deleting, enabling, disabling, and
- recalling breakpoints. Breakpoints are identified by breakpoint index
- numbers, which are numbers ranging from 0 to FF (hex). Breakpoint
- index numbers are assigned sequentially as breakpoints are added. The
- following table describes the breakpoint manipulation commands:
-
- BD Disable a breakpoint
- BE Enable a breakpoint
- BL List current breakpoints
- BPEEdit a breakpoint
- BPTUse breakpoint as template
- BC Clear (remove) a breakpoint
- BH Display breakpoint history
-
- Note: Refer to the SoftICE Command Reference for more information on
- each of these commands.
-
- Using Embedded Breakpoints
-
- It may be helpful for you to embed a breakpoint in your program source
- rather than setting a breakpoint with SoftICE. To embed a breakpoint
- in your program, do the following:
-
- 1 Place an INT 1 or INT 3 instruction at the desired point in the
- program source.
-
- 2 To enable SoftICE to pop up on such embedded breakpoints, use the
- following command:
-
- SET I1HERE ON ; for INT 1 breakpoints
- SET I3HERE ON ; for INT 3 breakpoints
-